#!/usr/local/bin/perl -w
#
# create_mta_xml.pl
# 
# Take and parse the MTA Weekend Service Advisories html file and
# create an XML file out of it.
#
# http://www.mta.info/nyct/service/subsrvnweekend.htm
# 
# NOTE: This is this in testing phases. If the language on the HTML
#       page changes then this script will have to change.
#
# Created: 5/4/07
# Modified: 5/22/07
# By: rhsieh@gmail.com
#

use strict;
use warnings;

use Getopt::Std;
use LWP::Simple;
use XML::Simple;
use File::Basename;
use POSIX qw(strftime);

# global variables and settings
my $HOMEDIR = `echo -n ~`;
my $MTA_SERV_URL  = "http://www.mta.info/nyct/service/subsrvnweekend.htm";
my $MTA_SERV_URL_DIR = dirname($MTA_SERV_URL);
my $MTA_SERV_FILE = "$HOMEDIR/mta/bin/subsrvnweekend.htm";
my $MTA_SERV_XML  = "$HOMEDIR/mta/feed/subsrvnweekend.xml";

# convert subway name to our naming convention
my %subwayNamesHash = (
	"uno"    => "1",
	"dos"    => "2",
	"tres"   => "3",
	"cuatro" => "4",
	"cinco"  => "5",
	"seis"   => "6",
	"siete"  => "7",
	"mtrain" => "m"
);


############################# MAIN #################################

my $DEBUG  = 0;
my $NODOWN = 0;

# check arguments
my %opts;
getopts("hdn", \%opts) || usage();
usage()     if $opts{h};
$DEBUG  = 1 if $opts{d};
$NODOWN = 1 if $opts{n};

print "Home Dir: $HOMEDIR\n";
print "MTA File: $MTA_SERV_FILE\n";    
print "MTA URL : $MTA_SERV_URL\n";    
print "MTA XML : $MTA_SERV_XML\n";    

unless ($NODOWN == 1) {
	my $responseCode = mirror($MTA_SERV_URL, $MTA_SERV_FILE);
	if (is_error($responseCode)) {
		die "Could not mirror $MTA_SERV_URL: $!";
	}
}

# process the html and make an rss feed out of it
my $mtaXML = createXML($MTA_SERV_FILE);

# write xml to a file
open(MTAXML_FH, ">$MTA_SERV_XML") ||
	die "Could not open/write to $MTA_SERV_XML: $!";
print MTAXML_FH $mtaXML;

exit();

########################### SUBROUTINE #############################
sub createXML {
	my $mtaFile = shift(@_);

	open(MTA_FH, "$mtaFile") ||
		die "Could not open $mtaFile: $!";

	# this is super hacky, since the HTML DOM is flawed
	my @subwaysArray;
	while (my $line = <MTA_FH>) {
		chomp($line);

		# extract the subway names and see if they match our list
		# we can rely on the fact that subway line info is contained
		# between the boundaries:
		# - <a name="(subway line)">
		# - <a href="#top">
		
		my ($subwayName) = ($line =~ /<a name="([a-z]+)">/);
		next if not defined($subwayName);

		$subwayName = $subwayNamesHash{$subwayName}
			if (exists($subwayNamesHash{$subwayName}));

		# XXX - for testing specific subways
		#next if ($subwayName !~ /^j$/);

		print "\n$subwayName\n" if ($DEBUG == 1);
		print "-----------------------------\n" if ($DEBUG == 1);

		my $subwayInfoBlock = "";
		while (my $line = <MTA_FH>) {
			chomp($line);
			$subwayInfoBlock .= $line;
			last if ($line =~ /<a href="#top">/);
		}

		# get rid of comments
		$subwayInfoBlock =~ s/<!--.*?-->//g;

		# grab whatevers in paragraph tags or <a href="#top">
		my %subwayInfo;
		my $i = 1;  # advisory iterator
		my $j = 1;  # detail iterator
		while ($subwayInfoBlock =~ /(<p>|<a href=".*?\.pdf">|<span.*?>)(.*?)(<\/p>|<a href="#top">|<\/a>)/ig) {
			my $noticeBlock = "$1$2$3";

			#print "*** $noticeBlock\n" if ($DEBUG == 1);

			# grab lines one by one dealing with each special case
			my $notice = undef;
			my $times  = undef;
			my @subwayChanges;
			while ($noticeBlock =~ /(.*?)(<\/p>|<br.*?>|<\/a>)/ig) {
				my $subwayChange = $1;

				# if $subwayChange contains ".pdf", add it current advisory
				# unless "pdf" is already defined then add to previous advisory
				if ($subwayChange =~ /"(.*\.pdf)".*PDF/) {
					my $pdf = "$MTA_SERV_URL_DIR/$1";
					if (($i > 1) && 
					    !(exists($subwayInfo{"advisory" . ($i - 1)}{pdf}))) {
						$subwayInfo{"advisory" . ($i - 1)}{pdf} = $pdf;
					} else {
						$subwayInfo{"advisory$i"}{pdf} = $pdf;
					}
					print "\t$pdf\n" if ($DEBUG == 1);
					next;
				}

				# some formatting cleanup
				$subwayChange =~ s/<.*?>//g;
				$subwayChange =~ s/&\w+;//g;
				$subwayChange =~ s/^\s+//; $subwayChange=~ s/\s+$//;

				# skip empty lines -- keep for now
				#next if ($subwayChange =~ /^$/);
				
				# if we don't have a "bold" section, then we have a notice, otherwise
				# just pad to previous list of subwayChanges
				
				# if we have a time block, the main notice is done
				if ((not defined($notice)) && ($subwayChange =~ /(diversions|remains closed|No service)/i)) {
					$notice = combineLines(@subwayChanges) . $subwayChange;
					@subwayChanges = ();
				}
				elsif (($subwayChange =~ /(.*?)(Weekends,|Weekends until|Weekend,|Late night,|All times|Fri|Sat|Sun|Mon)(.*)/)) {
					# take into when there are two subway notices in a noticeBlock
					if (defined($times)) {
						$times .= "\n$1$2$3";
					}
					else {
						$notice = $notice . combineLines(@subwayChanges) . $1;
						$times  = "$2$3";
						@subwayChanges = ();
					}
				}
				else {
					push(@subwayChanges, $subwayChange);
				}
			}

			# if notice is undefined still then add it to the details in previous advisory
			if (not defined($notice)) {
				while (my $subwayChange = shift(@subwayChanges)) {
					chomp($subwayChange);
					$subwayInfo{"advisory" . ($i - 1)}{"details"} .= "$subwayChange\n";
					$j++;
				}
				next;
			}

			print "$notice\n"  if ($DEBUG == 1);
			print "\t$times\n" if (defined($times) && ($DEBUG == 1));

			$subwayInfo{"advisory$i"}{description} = $notice;
			$subwayInfo{"advisory$i"}{times}       = $times 
				if defined($times);
			while (my $subwayChange = shift(@subwayChanges)) {
				chomp($subwayChange);
				$subwayInfo{"advisory$i"}{"details"} .= "$subwayChange\n";
				$j++;
			}

			$j = 1;
			$i++;
		}
		push(@subwaysArray, {
			advisory => [ values %subwayInfo ],
			name => $subwayName
		});
	}
	close(MTA_FH);

	# set up some other properties
	my %mtaHash = (
			"source"      => $MTA_SERV_URL,
			"lastupdated" => strftime("%a %b %e %H:%M:%S %Y", localtime()),
			"subways"     => { "subway" => [ @subwaysArray ] }
	);

	# now actually create the xml
	my $xmlSimple = XML::Simple->new();
	return $xmlSimple->XMLout(\%mtaHash,
		rootname => "nyctransitinfo",
		xmldecl  => 1,
		noattr   => 1,
	);
}

sub combineLines {
	my $joined = "";
	my $firstLine = 1;

	# add new lines only between lines when necessary
	foreach my $line (@_) {
		if (($line =~ /^to /) || ($joined =~ / to$/)) {
			$joined .= " " . $line;
		}
		elsif ($firstLine == 0) {
			$joined .= "\n" . $line;
		}
		else {
			$joined = $line;
			$firstLine = 0;
		}
	}

	return $joined;
}

sub usage {
	print STDERR << "EOF";
$0 [-hdn]
 -h : help
 -d : debugging mode
 -n : don't download html file
EOF
	exit;
}

